package org.jsola.hr.service.excel;

import com.alibaba.excel.context.AnalysisContext;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsola.common.BeanKit;
import org.jsola.common.DateKit8;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.DateUtils;
import org.jsola.hr.constant.EmpSocStatus;
import org.jsola.hr.dto.ImportDecreaseDTO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.EmpSocPlanDO;
import org.jsola.hr.entity.EmpSocRelatedDO;
import org.jsola.hr.service.*;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * @author zhr
 */
@EqualsAndHashCode(callSuper = true)
@Slf4j
@Data
public class ImportDecreaseListener extends BaseAnalysisEventListener<ImportDecreaseDTO> {

    /**
     * 表头
     */
    private Map<Integer, String> allHeadMap;

    /**
     * 成功列表
     */
    private List<ImportDecreaseDTO> successList = new ArrayList<>();

    /**
     * 失败列表
     */
    private List<ImportDecreaseDTO> failList = new ArrayList<>();

    /**
     * 公司Id
     */
    private String companyId;

    /**
     * 社保子项
     */
    private static final Integer SOC_ITEM = 1;

    /**
     * 医保子项
     */
    private static final Integer ME_ITEM = 3;

    /**
     * 公积金子项
     */
    private static final Integer PF_ITEM = 2;

    /**
     * List最大盛装数据条数
     */
    private static final Integer MAX_COUNT = 1000;

    /**
     * Excel导入数据条目
     */
    private List<ImportDecreaseDTO> dataList = new ArrayList<>();

    @Override
    public void invoke(ImportDecreaseDTO data, AnalysisContext context) {
        // 当前行号
        int row = context.readRowHolder().getRowIndex();
        if (!ObjectUtils.isEmpty(data.getName()) && "示例员工张三".equals(data.getName())) {
            return;
        }
        if (ObjectUtils.isEmpty(data.getWhetherSocDecrease())) {
            data.setWhetherSocDecrease(false);
        }
        if (ObjectUtils.isEmpty(data.getWhetherMeDecrease())) {
            data.setWhetherMeDecrease(false);
        }
        if (ObjectUtils.isEmpty(data.getWhetherSealed())) {
            data.setWhetherSealed(false);
        }
        checkError(data);
        dataList.add(data);
    }

    /**
     * 入库
     */
    @Override
    public void saveData() {
        IEmpSocPlanService empSocPlanService = BeanKit.getBean(IEmpSocPlanService.class);
        if (CollectionUtils.isEmpty(successList) && CollectionUtils.isEmpty(failList)) {
            throw new ParamException("导入数据为空");
        }
        log.info("{}条数据，开始存储数据库！", dataList.size());
        empSocPlanService.importDecreaseSaveData(successList, companyId, tokenUser);

    }

    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        allHeadMap = headMap;
        List<String> checkHeadList = new ArrayList<>();
        checkHeadList.add("姓名");
        checkHeadList.add("证件号码");
        checkHeadList.add("是否社保减员");
        checkHeadList.add("社保减员年月");
        checkHeadList.add("是否医保减员");
        checkHeadList.add("医保减员年月");
        checkHeadList.add("是否公积金减员");
        checkHeadList.add("公积金减员年月");
        checkHeadList.add("服务费");
        try {
            for (Integer headRow : headMap.keySet()) {
                String importHead = headMap.get(headRow);
                String checkHead = checkHeadList.get(headRow);
                if (!checkHead.equals(importHead)) {
                    throw new ParamException("表头第" + (headRow + 1) + "列应为" + checkHead);
                }
            }
        } catch (IndexOutOfBoundsException e) {
            throw new ParamException("不可增加减员模板表头");
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        if (!CollectionUtils.isEmpty(successList)) {
            saveData();
        }
    }

    private void checkError(ImportDecreaseDTO data) {
        IEmpInfoService empInfoService = BeanKit.getBean(IEmpInfoService.class);
        IEmpSocPlanService empSocPlanService = BeanKit.getBean(IEmpSocPlanService.class);
        IEmpSocRelatedService empSocRelatedService = BeanKit.getBean(IEmpSocRelatedService.class);
        boolean haveError = false;
        Set<String> errorColumn = new HashSet<>();
        Map<String, String> errorInfo = new HashMap<>(8);
        String name = data.getName();
        if (StringUtils.isEmpty(name)) {
            haveError = true;
            errorColumn.add("name");
            data.setName("--");
            errorInfo.put("name", "姓名不得为空");
        } else {
            String idCard = data.getIdCard();
            if (StringUtils.isEmpty(idCard)) {
                haveError = true;
                errorColumn.add("idCard");
                data.setIdCard("--");
                errorInfo.put("idCard", "证件号码不得为空");
            } else {
                EmpInfoDO empInfoDO = empInfoService.selectIdCardAndPhone(idCard, name, companyId, tokenUser);
                if (ObjectUtils.isEmpty(empInfoDO)) {
                    haveError = true;
                    errorColumn.add("name");
                    errorInfo.put("name", "员工无法匹配");
                } else {
                    List<Integer> checkStatusList = Arrays.asList(EmpSocStatus.ATTRITION.getValue(),
                            EmpSocStatus.STOP_SOC.getValue(), EmpSocStatus.NOT_SOC.getValue());
                    EmpSocRelatedDO empSocRelatedDO =
                            empSocRelatedService.selectByEmpId(empInfoDO.getId(), tokenUser.getSiteId());
                    if (data.getWhetherSocDecrease()) {
                        String stopSocDate = data.getStopSocDate();
                        Date socIncreaseDate = empSocRelatedDO.getSocIncreaseDate();
                        if (StringUtils.isEmpty(stopSocDate)) {
                            haveError = true;
                            errorColumn.add("stopSocDate");
                            data.setStopSocDate("--");
                            errorInfo.put("stopSocDate", "社保停保年月不得为空");
                        } else if (checkDateFormat(stopSocDate)) {
                            haveError = true;
                            errorColumn.add("stopSocDate");
                            errorInfo.put("stopSocDate", "社保停保年月格式有误");
                        } else if (checkDateGreaterThanCurrent(stopSocDate)) {
                            haveError = true;
                            errorColumn.add("stopSocDate");
                            errorInfo.put("stopSocDate", "社保停保年月必须大于等于当前日期");
                        } else if (checkStatusList.contains(empSocRelatedDO.getSocState())) {
                            // 判断是否已经是减员状态了
                            haveError = true;
                            errorColumn.add("stopSocDate");
                            errorInfo.put("stopSocDate", "员工社保未参保或已经是减员/停保状态");
                        } else if (!ObjectUtils.isEmpty(socIncreaseDate)
                                && checkIncreaseDate(stopSocDate, socIncreaseDate)) {
                            haveError = true;
                            errorColumn.add("stopSocDate");
                            errorInfo.put("stopSocDate", "减员月份不得早于参保时间；");
                        } else {
                            List<EmpSocPlanDO> empSocPlanList = empSocPlanService
                                    .selectPlanByEmpId(empInfoDO.getId(), SOC_ITEM, tokenUser);
                            if (!CollectionUtils.isEmpty(empSocPlanList)) {
                                haveError = true;
                                errorColumn.add("stopSocDate");
                                errorInfo.put("stopSocDate", "该员工已存在社保减员计划;");
                            }
                        }

                    }
                    if (data.getWhetherMeDecrease()) {
                        String stopMeDate = data.getStopMeDate();
                        Date meIncreaseDate = empSocRelatedDO.getMeIncreaseDate();
                        if (StringUtils.isEmpty(stopMeDate)) {
                            haveError = true;
                            errorColumn.add("stopMeDate");
                            data.setStopMeDate("--");
                            errorInfo.put("stopMeDate", "医保停保年月不得为空");
                        } else if (checkDateFormat(stopMeDate)) {
                            haveError = true;
                            errorColumn.add("stopMeDate");
                            errorInfo.put("stopMeDate", "医保停保年月格式有误");
                        } else if (checkDateGreaterThanCurrent(stopMeDate)) {
                            haveError = true;
                            errorColumn.add("stopMeDate");
                            errorInfo.put("stopMeDate", "医保停保年月必须大于等于当前日期");
                        } else if (checkStatusList.contains(empSocRelatedDO.getMeState())) {
                            // 判断是否已经是减员状态了
                            haveError = true;
                            errorColumn.add("stopMeDate");
                            errorInfo.put("stopMeDate", "员工医保未参保或已经是减员/停保状态");
                        } else if (!ObjectUtils.isEmpty(meIncreaseDate)
                                && checkIncreaseDate(stopMeDate, meIncreaseDate)) {
                            haveError = true;
                            errorColumn.add("stopMeDate");
                            errorInfo.put("stopMeDate", "减员月份不得早于参保时间;");
                        } else {
                            List<EmpSocPlanDO> empSocPlanList = empSocPlanService
                                    .selectPlanByEmpId(empInfoDO.getId(), ME_ITEM, tokenUser);
                            if (!CollectionUtils.isEmpty(empSocPlanList)) {
                                haveError = true;
                                errorColumn.add("stopMeDate");
                                errorInfo.put("stopMeDate", "该员工已存在医保减员计划;");
                            }
                        }
                    }
                    if (data.getWhetherSealed()) {
                        String sealedDate = data.getSealedDate();
                        Date pfIncreaseDate = empSocRelatedDO.getPfIncreaseDate();
                        if (StringUtils.isEmpty(sealedDate)) {
                            haveError = true;
                            errorColumn.add("sealedDate");
                            data.setSealedDate("--");
                            errorInfo.put("sealedDate", "公积金停保年月不得为空");
                        } else if (checkDateFormat(sealedDate)) {
                            haveError = true;
                            errorColumn.add("sealedDate");
                            errorInfo.put("sealedDate", "公积金停保年月格式有误");
                        } else if (checkDateGreaterThanCurrent(sealedDate)) {
                            haveError = true;
                            errorColumn.add("sealedDate");
                            errorInfo.put("sealedDate", "公积金停保年月必须大于等于当前日期");
                        } else if (checkStatusList.contains(empSocRelatedDO.getPfState())) {
                            // 判断是否已经是减员状态了
                            haveError = true;
                            errorColumn.add("sealedDate");
                            errorInfo.put("sealedDate", "员工公积金未参保或已经是减员/停保状态");
                        } else if (!ObjectUtils.isEmpty(pfIncreaseDate)
                                && checkIncreaseDate(sealedDate, pfIncreaseDate)) {
                            // 判断减员时间是否在增员时间之前
                            haveError = true;
                            errorColumn.add("sealedDate");
                            errorInfo.put("sealedDate", "减员月份不得早于参保时间；");
                        } else {
                            List<EmpSocPlanDO> empSocPlanList = empSocPlanService
                                    .selectPlanByEmpId(empInfoDO.getId(), PF_ITEM, tokenUser);
                            if (!CollectionUtils.isEmpty(empSocPlanList)) {
                                haveError = true;
                                errorColumn.add("sealedDate");
                                errorInfo.put("sealedDate", "该员工已存在公积金减员计划;");
                            }
                        }
                    }
                    if (!StringUtils.isEmpty(data.getServiceCost())) {
                        try {
                            BigDecimal service = new BigDecimal(data.getServiceCost());
                            if(service.compareTo(BigDecimal.ZERO) < 0){
                                haveError = true;
                                errorColumn.add("serviceCost");
                                errorInfo.put("serviceCost", "服务费不能为负数");
                            } else {
                                // 四舍五入保留两位小数
                                data.setServiceCost(service.setScale(2, RoundingMode.HALF_UP).toPlainString());
                            }
                        } catch (Exception e) {
                            haveError = true;
                            errorColumn.add("serviceCost");
                            errorInfo.put("serviceCost", "服务费格式错误");
                        }
                    }
                    data.setEmpId(empInfoDO.getId());
                }
            }
        }
        if (haveError) {
            data.setErrorColumn(errorColumn);
            data.setErrorInfo(errorInfo);
            failList.add(data);
        } else {
            successList.add(data);
        }
    }

    /**
     * true 格式错误
     */
    private Boolean checkDateFormat(String date) {
        String replaceData = date.replace("/", "-");
        String replaceDataAdd = replaceData + "-01";
        try {
            DateKit8.parseDate(replaceDataAdd);
        } catch (Exception e) {
            return true;
        }
        return false;
    }

    /**
     * 判断excel键入的时间是否小于当前时间
     */
    private Boolean checkDateGreaterThanCurrent(String date) {
        String replaceDate = date.replace("/", "");
        // excel键入的时间
        int scannerDate = Integer.parseInt(replaceDate);
        // 当前时间
        int currentDate = Integer.parseInt(DateUtils.getYearMonthStr(new Date()));
        return scannerDate < currentDate;
    }

    /**
     * 判断输入的减员时间是否在增员时间之前
     */
    private Boolean checkIncreaseDate(String date, Date increaseDate) {
        String replaceDate = date.replace("/", "");
        // excel键入的时间
        int scannerDate = Integer.parseInt(replaceDate);
        // 当前时间
        int currentDate = Integer.parseInt(DateUtils.getYearMonthStr(increaseDate));
        return scannerDate < currentDate;
    }
}


